package Main;


import java.awt.Color;
import java.awt.image.BufferedImage;



public class StegMethods {

	//Needs the bufferedImage to be encrypted and the message string to be encrypted passed in. Will do everything in house and pass back
	//the encrypted bufferedImage. Need access to the picture class and need a modified Picture constructor that allows bufferedImage as a parameter.
	//Otherwise I need the file passed to me instead of the BufferedImage, or I need all of picture to be public and static
	public static BufferedImage encryptText(BufferedImage img, String message) {
		if(img == null){
			System.out.println("null img");
		}
		System.out.println("in encrypt");
		Picture pic = new Picture(img, "Image to be encrypted");
		Color[][] source = pic.getColors();
		Color[][] c = new Color[source.length][source[0].length];
		int p = getPrimes(source, message);
		int count = 0, mY = 0, interval = p;
		String clearMsg = message;
		int [][] m = new int[clearMsg.length()][3];
		
		for (int i = 0; i < m.length; i++) {
			char ch = clearMsg.charAt(i);
			int r = ch / 3;
			int g = r;
			int b = ch - (r + g);
			m[i][0] = r;
			m[i][1] = g;
			m[i][2] = b;
		}

		for (int y = 0; y < c.length; y++) {
			for (int x = 0; x < c[0].length; x++) {
				c[y][x] = source[y][x];
				count++;
				if (count == interval) {
					Color color = source[y][x];
					int r = color.getRed();
					int g = color.getGreen();
					int b = color.getBlue();
					if (r < 128)
						r = r + m[mY][0];
					else
						r = r - m[mY][0];
					if (g < 128)
						g = g + m[mY][1];
					else
						g = g - m[mY][1];
					if (b < 128)
						b = b + m[mY][2];
					else
						b = b - m[mY][2];
					c[y][x] = new Color(r, g, b);
					interval = p + interval;
					mY++;

				}
			}
		}
		pic.setColors(c);
		System.out.println("out encrypt");
		return pic.image;
	}

	//Need the encrypted bufferedImage to the encrypted text passed in first and the original clean bufferedImage passed in second.
	//Will return the message char string
	public static String decryptText(BufferedImage encrypted, BufferedImage clean) {
		System.out.println("in dycrypt");
		Picture p = new Picture(clean, "Clean Image");
		Picture p2 = new Picture(encrypted, "Encrypted Image");
		Color[][] source2 = p.getColors();
		Color[][] encrypt2 = p2.getColors();
		int r, g, b, r1, g1, b1;
		char ch = ' ';
		String s = " ";
		for (int y = 0; y < encrypt2.length; y++) {
			for (int x = 0; x < encrypt2[0].length; x++) {
				Color source1 = source2[y][x];
				r = source1.getRed();
				g = source1.getGreen();
				b = source1.getBlue();
				Color encrypt1 = encrypt2[y][x];
				r1 = encrypt1.getRed();
				g1 = encrypt1.getGreen();
				b1 = encrypt1.getBlue();
				int red = Math.abs(r - r1);
				int blue = Math.abs(b - b1);
				int green = Math.abs(g - g1);
				ch = (char) (red + green + blue);
				if ((int)ch > 0){
					System.out.print(ch);
					s += ch;
				}
			}
		}
		System.out.println(s);
		return s;

	}
	
	//Needs the BufferedImage that is going to be visible passed in first and the bufferedImage that is going to be hidden passed in second. 
	//Pictures need to be the same size or will throw and exception. I can make a try and catch block if need be.
	public static BufferedImage encryptAlpha(BufferedImage visable, BufferedImage hidden) {
		Picture pic = new Picture(visable, "Visable Picture");
		Color[][] clean = pic.getColors();
		Picture pic2=new Picture(hidden, "hidden Picture");
		Color[][] encrypt= pic2.getColors();
		Color c [][]= new Color[clean.length][clean[0].length];
		for (int x = 0; x < c[0].length; x++)
			for (int y = 0; y < c.length; y++) {
				double r = ((encrypt[y][x].getRed() * .1) + (clean[y][x]
						.getRed() * .9));
				double g = ((encrypt[y][x].getGreen() * .1) + (clean[y][x]
						.getGreen() * .9));
				double b = ((encrypt[y][x].getBlue() * .1) + (clean[y][x]
						.getBlue() * .9));
				c[y][x] = new Color((int)r, (int)g, (int)b);
			}
		pic.setColors(c);
		return pic.image;
	}
	
	//Needs the encrytedAlpha buffered image passed in first and the the clean source cover bufferedImage passed in second (the image that you 
	//see when you look at the encrypted alpha buffered image)
	public static BufferedImage decryptAlpha(BufferedImage encryptedMain, BufferedImage cleanVisable) {
		Picture pic = new Picture(encryptedMain, "Encrypted Image");
		Color[][] encrypted = pic.getColors();
		Picture p = new Picture(cleanVisable, "Clean Visable Image");
		Color[][] clean = p.getColors();
		Color [][] c = new Color[clean.length][clean[0].length];
		for (int x = 0; x < c[0].length; x++)
			for (int y = 0; y < c.length; y++) {
				double r = (encrypted[y][x].getRed() - (clean[y][x].getRed() * .9));
				double g = (encrypted[y][x].getGreen() - (clean[y][x].getGreen() * .9));
				double b = (encrypted[y][x].getBlue() - (clean[y][x].getBlue() * .9));
				c[y][x] = new Color((int)(r * 10+.5), (int)(g * 10+.5), (int)(b * 10+.5));
			}
		pic.setColors(c);
		return pic.image;
	}
	
	//Needs the visible bufferedImage passed in first (the one not being hidden) and the bufferedImage to be hidden passed in second. Returns the 
	//encrypted image.
	public static BufferedImage encryptByte(BufferedImage encrypted, BufferedImage hidden) {
		Picture t = new Picture(hidden, "Hidden Image");
		Picture pic = new Picture(encrypted, "Encrypted Image");
		Color[][] c = pic.getColors();
		Color[][] target = t.getColors();
		for (int y = 0; y < c.length; y++) {
			for (int x = 0; x < c[0].length; x++) {
				Color hold = c[y][x];
				int r = (hold.getRed() & 0x000000F0);
				int g = (hold.getGreen() & 0x000000F0);
				int b = (hold.getBlue() & 0x0F0);

				Color hold4tar = target[y][x];
				int r1 = (hold4tar.getRed() & 0x0F0);
				int g1 = (hold4tar.getGreen() & 0x0F0);
				int b1 = (hold4tar.getBlue() & 0x0F0);

				int s1 = (r1 >>> 4);
				int s2 = (g1 >>> 4);
				int s3 = (b1 >>> 4);

				int n1 = (r | s1);
				int n2 = (g | s2);
				int n3 = (b | s3);

				c[y][x] = new Color(n1, n2, n3);
			}
		}
		pic.setColors(c);
		return pic.image;
	}
	
	//Needs the encryptedByte bufferedImage passed in. Returns the hidden bufferedImage.
	public static BufferedImage decryptByte(BufferedImage encrypted) {
		Picture pic = new Picture(encrypted, "Encrypted Image");
		Color[][] e = pic.getColors();
		Color[][] target = new Color[e.length][e[0].length];
		for (int y = 0; y < e.length; y++) {
			for (int x = 0; x < e[0].length; x++) {
				Color hold = e[y][x];
				int r = (hold.getRed() & 0x0F);
				int g = (hold.getGreen() & 0x0F);
				int b = (hold.getBlue() & 0x0F);

				int s1 = (r << 4);
				int s2 = (g << 4);
				int s3 = (b << 4);

				target[y][x] = new Color(s1, s2, s3);
			}
		}
		pic.setColors(target);
		return pic.image;
	}
	private static int getPrimes(Color[][] c, String clearMsg) {
		int N = c[0].length * c.length;
		int q = (N / clearMsg.length());
		int p = 0;
		boolean[] isPrime = new boolean[q + 1];
		for (int i = 2; i <= q; i++) {
			isPrime[i] = true;
		}
		for (int i = 2; i * i <= q; i++) {
			if (isPrime[i]) {
				for (int j = i; i * j <= q; j++) {
					isPrime[i * j] = false;
				}
			}
		}
		for (int i = 0; i < isPrime.length; i++) {
			if (isPrime[i] == true) {
				p = i;
			}
		}
		return p;
	}
	}
